#include "server.h"
#include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

static int count = 0;
static int data_max = 8;
static int ssocket = -1;
static int sockets[1024];
static PARKINGLOT parkinglot = {0};

static void copy(char *dest, const char *src, const int count) {
    int i;
    for (i = 0; i < count; i++)
        dest[i] = src[i];
}

static void error_handle(const char *errmsg) {
    perror(errmsg);
    exit(1);
}

void server_init(const char *port, const int dataMax) {
    int opt = 1;
    struct sockaddr_in address;
    data_max = dataMax;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(atoi(port));
    if ((ssocket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        error_handle("server_init socket error!\n");
    setsockopt(ssocket, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
    if (bind(ssocket, (struct sockaddr *)&address, sizeof(address)) == -1)
        error_handle("server_init bind error!\n");
    if (listen(ssocket, QUEUE_MAX) == -1)
        error_handle("server_init listen error!\n");
    printf("server_init server init success!\n");
}

void server_run() {
    int client;
    pthread_t tid;
    while (1) {
        client = accept(ssocket, NULL, NULL);
        pthread_create(&tid, NULL, client_handle, (void *)&client);
    }
}

void save_client(const int client) {
    sockets[count++] = client;
}

void remove_clinet(const int client) {
    int i, k, endk;
    for (i = 0; i < count; i++)
        if (sockets[i] == client) {
            for (k = i, endk = count - 1; k < endk; k++)
                sockets[k] = sockets[k + 1];
            break;
        }
    count--;
}

void send_all(const char *buf, const int size) {
    int i;
    for (i = 0; i < count; i++)
        write(sockets[i], buf, size);
}

void *client_handle(void *arg) {
    char buf[data_max];
    int client = *(int *)arg;
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    save_client(client);
    send_controller_status(client);
    getpeername(client, (struct sockaddr *)&addr, &len);
    printf("[%s] online...\n", inet_ntoa(addr.sin_addr));
    while (1) {
        memset(buf, 0, sizeof(buf));
        if (read(client, buf, sizeof(buf)) == 0) {
            printf("[%s] offline...\n", inet_ntoa(addr.sin_addr));
            remove_clinet(client);
            close(client);
            pthread_exit(NULL);
        }
        save_controller_status(buf, data_max);
        send_all(buf, data_max);
    }
}

void save_controller_status(const char *buf, const int size) {
    int i;
    printf("data: [");
    for (i = 0; i < size; i++)
        printf(i == 0 ? "%x" : ", %x", buf[i]);
    printf("]\n");
    switch ((unsigned char)buf[0]) {
    case 0x1: // 灯
        printf("lamp\n");
        copy(parkinglot.lamp, buf, sizeof(parkinglot.lamp));
        break;

    case 0x2: // 栏杆
        printf("railing\n");
        copy(parkinglot.railing, buf, sizeof(parkinglot.railing));
        break;

    case 0x3: // 摄像头
        printf("camera\n");
        copy(parkinglot.camera, buf, sizeof(parkinglot.camera));
        break;

    case 0x4: // 距离
        printf("distance\n");
        copy(parkinglot.distance, buf, sizeof(parkinglot.distance));
        break;

    case 0x5: // 温度
        printf("temperature\n");
        copy(parkinglot.temperature, buf, sizeof(parkinglot.temperature));
        break;

    case 0x6: // 湿度
        printf("humidity\n");
        copy(parkinglot.humidity, buf, sizeof(parkinglot.humidity));
        break;

    case 0x7: // 海拔
        printf("altitude\n");
        copy(parkinglot.altitude, buf, sizeof(parkinglot.altitude));
        break;

    case 0x8: // 气压
        printf("pressure\n");
        copy(parkinglot.pressure, buf, sizeof(parkinglot.pressure));
        break;

    case 0x9: // 烟雾浓度
        printf("concentration\n");
        copy(parkinglot.concentration, buf, sizeof(parkinglot.concentration));
        break;

    case 0xa: // 烟雾阈值
        printf("threshold\n");
        copy(parkinglot.threshold, buf, sizeof(parkinglot.threshold));
        break;

    case 0xb: // 光照强度
        printf("illumination\n");
        copy(parkinglot.illumination, buf, sizeof(parkinglot.illumination));
        break;

    case 0xc: // 车位总数
        printf("total\n");
        copy(parkinglot.total, buf, sizeof(parkinglot.total));
        break;

    case 0xd: // 车位剩余
        printf("remainder\n");
        copy(parkinglot.remainder, buf, sizeof(parkinglot.remainder));
        break;

    default:
        printf("default\n");
        break;
    }
}

void send_controller_status(int client) {
    printf("send_controller_status client: %d", client);
    char buf[data_max];
    // 灯
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.lamp, sizeof(parkinglot.lamp));
    write(client, buf, data_max);
    // 栏杆
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.railing, sizeof(parkinglot.railing));
    write(client, buf, data_max);
    // 摄像头
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.camera, sizeof(parkinglot.camera));
    write(client, buf, data_max);
    // 距离
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.distance, sizeof(parkinglot.distance));
    write(client, buf, data_max);
    // 温度
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.temperature, sizeof(parkinglot.temperature));
    write(client, buf, data_max);
    // 湿度
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.humidity, sizeof(parkinglot.humidity));
    write(client, buf, data_max);
    // 海拔
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.altitude, sizeof(parkinglot.altitude));
    write(client, buf, data_max);
    // 气压
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.pressure, sizeof(parkinglot.pressure));
    write(client, buf, data_max);
    // 烟雾浓度
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.concentration, sizeof(parkinglot.concentration));
    write(client, buf, data_max);
    // 烟雾阈值
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.threshold, sizeof(parkinglot.threshold));
    write(client, buf, data_max);
    // 光照强度
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.illumination, sizeof(parkinglot.illumination));
    write(client, buf, data_max);
    // 车位总数
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.total, sizeof(parkinglot.total));
    write(client, buf, data_max);
    // 车位剩余
    memset(buf, 0, sizeof(buf));
    copy(buf, parkinglot.remainder, sizeof(parkinglot.remainder));
    write(client, buf, data_max);
}
